﻿///////////////////////////////////////////////////////////////////////////////
//
//  This source is part of the  "Managed Task Framework.NET Runtime"  (MTF.NET Runtime).
//
//
//  Copyright (c) 2011, Multicore Consulting Limited (UK)
//  All rights reserved.
//  http://www.multicoreconsulting.co.uk
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions
//  are met:
//
//  -  Redistributions of source code must retain the above copyright
//     notice, this list of conditions and the following disclaimer.
//  -  Redistributions in binary form must reproduce the above copyright
//     notice, this list of conditions and the following disclaimer in
//     the documentation and/or other materials provided with the
//     distribution.
//  -  Neither the name of Multicore Consulting Limited nor the names of
//     its contributors may be used to endorse or promote products
//     derived from this software without specific prior written
//     permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//  COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//  POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MTFOrg.MTF.MTFRuntime
{
    public class Connection : IConnection
    {
        /// <summary>
        /// The connection point from which this connection was made.
        /// </summary>
        protected IConnectionPoint m_SourceConnectionPoint;

        /// <summary>
        /// Ordering value for the source end of the connection.
        /// </summary>
        protected int m_SourceOrder;

        /// <summary>
        /// The connection point to which this connection was made.
        /// </summary>
        protected IConnectionPoint m_TargetConnectionPoint;

        /// <summary>
        /// Ordering value for the target end of the connection.
        /// </summary>
        protected int m_TargetOrder;

        /// <summary>
        /// The unique identifier for this connection.
        /// </summary>
        protected Guid m_Id;

        /// <summary>
        /// Dictionary of properties associated with this connection.
        /// </summary>
        protected Dictionary<string, ConnectionProperty> m_Properties;

        /// <summary>
        /// Link to the task that owns this connection.
        /// </summary>
        protected ITask m_ParentTask;

        /// <summary>
        /// Gets the connection point from which this connection was made.
        /// </summary>
        public IConnectionPoint SourceConnectionPoint
        {
            get { return m_SourceConnectionPoint; }
        }

        /// <summary>
        /// Gets the ordering value for the source end of the connection.
        /// </summary>
        public int SourceOrder
        {
            get { return m_SourceOrder; }
        }

        /// <summary>
        /// Gets the connection point to which this connection was made.
        /// </summary>
        public IConnectionPoint TargetConnectionPoint
        {
            get { return m_TargetConnectionPoint; }
        }

        /// <summary>
        /// Gets the ordering value for the target end of the connection.
        /// </summary>
        public int TargetOrder
        {
            get { return m_TargetOrder; }
        }

        /// <summary>
        /// Gets the unique identifier for this connection.
        /// </summary>
        public Guid Id
        {
            get { return m_Id; }
        }

        /// <summary>
        /// Gets and sets the user data tagged onto this connection.
        /// </summary>
        public object Tag
        {
            get { throw new System.Exception("Data can only be tagged to a located connection."); }
            set { throw new System.Exception("Data can only be tagged to a located connection."); }
        }

        /// <summary>
        /// Gets the task that owns this connection.
        /// </summary>
        public ITask ParentTask
        {
            get { return m_ParentTask; }
        }

        /// <summary>
        /// Constructor with no properties.
        /// </summary>
        /// <param name="parentTask">Task that owns the connection</param>
        /// <param name="connectionPoints">Connection points at either end</param>
        public Connection(
            IConnectionPoint sourceConnectionPoint,
            int sourceOrder,
            IConnectionPoint targetConnectionPoint,
            int targetOrder)
        {
            // Create properties dictionary
            m_Properties = new Dictionary<string, ConnectionProperty>();

            // Set up out-bound links
            m_SourceConnectionPoint = sourceConnectionPoint;
            m_SourceOrder = sourceOrder;
            m_TargetConnectionPoint = targetConnectionPoint;
            m_TargetOrder = targetOrder;

            m_Id = Guid.NewGuid();
        }

        /// <summary>
        /// Constructor with properties.
        /// </summary>
        /// <param name="parentTask">Task that owns the connection</param>
        /// <param name="sourceConnectionPoint">Connection point to connect from</param>
        /// <param name="sourceOrder">Ordering value for the source end</param>
        /// <param name="targetConnectionPoint">Connection point to connect to</param>
        /// <param name="targetOrder">Ordering value for the target end</param>
        /// <param name="connectionProperties">Connection properties</param>
        public Connection(
            ITask parentTask,
            IConnectionPoint sourceConnectionPoint,
            int sourceOrder,
            IConnectionPoint targetConnectionPoint,
            int targetOrder,
            IEnumerable<ConnectionProperty> connectionProperties)
        {
            // Create properties dictionary
            m_Properties = new Dictionary<string, ConnectionProperty>();

            // Set up out-bound links
            m_ParentTask = parentTask;
            m_SourceConnectionPoint = sourceConnectionPoint;
            m_SourceOrder = sourceOrder;
            m_TargetConnectionPoint = targetConnectionPoint;
            m_TargetOrder = targetOrder;

            m_Id = Guid.NewGuid();

            // Add each property to the property dictionary
            foreach (ConnectionProperty prop in (List<ConnectionProperty>)connectionProperties)
            {
                if (this.m_Properties.ContainsKey(prop.Name))
                    throw new DuplicateConnectionPropertyException(prop.Name);

                //if (!targetConnectionPoint.PropConstraints[prop.Name].ConnectionPropertyIsCompliant(prop))
                //   throw new Exception.PropertyNotCompliantException(prop.Name, targetConnectionPoint.ParentTask.Name);

                this.m_Properties.Add(prop.Name, prop);
            }
        }

        /// <summary>
        /// Gets the property with the specified name.
        /// </summary>
        /// <param name="name">Name of property to retrieve</param>
        /// <returns>Property with specified name or null if property doesn't exist</returns>
        public ConnectionProperty GetProperty(string name)
        {
            ConnectionProperty property = null;
            m_Properties.TryGetValue(name, out property);
            return property;
        }
    }
}
